package com.grandtech.insurance.common.db.jdbc.pg;


import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.grandtech.insurance.common.db.jdbc.sql.ReflectUtil;
import com.grandtech.insurance.common.utils.DateUtil;
import com.grandtech.insurance.common.utils.GsonFactory;
import com.grandtech.insurance.common.utils.ObjectUtil;
import com.grandtech.insurance.common.utils.trans.Transformation;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.GeoJson;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public final class FeatureUtil {

    /**
     * 装配feature
     *
     * @param feature
     * @return
     */
    public static Feature assembleFeature(Feature feature) {
        String areaCode = FeatureUtil.getFeatureAttributeAsT(feature, "qhdm");
        if (areaCode == null) new Throwable("Feature 属性异常！");
        //DictService dictService = SpringBeanUtil2.getBean(DictService.class);
        /*if (!feature.hasProperty("dkbm")) {
            String landNum = dictService.getLandNum(areaCode);
            feature.addStringProperty("dkbm", landNum);
        }*/
        return feature;
    }

    /**
     * **************************************************************************************************
     */
    public static Feature featureInsertBeforeTile(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature = assembleFeature(feature);
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.ADD.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.UN.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }

    public static Feature featureInsertAfterTileOK(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.ADD.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.ED.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }

    public static Feature featureInsertAfterTileFail(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.ADD.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.UN.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }

    public static Feature featureDelBeforeTile(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.DEL.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.UN.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }

    public static Feature featureDelAfterTileOk(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.DEL.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.ED.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }

    public static Feature featureDelAfterTileFail(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.DEL.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.UN.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }


    public static Feature featureUpDateBeforeTile(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.MODIFY.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.UN.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }

    public static Feature featureUpDateAfterTileOk(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.MODIFY.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.ED.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }

    public static Feature featureUpDateAfterTileFail(Feature feature) {
        if (feature.properties() == null) feature = Feature.fromGeometry(feature.geometry(), new JsonObject());
        feature.addNumberProperty(Constant.FeatureStatus.FEATURE_STATUS, Constant.FeatureStatus.MODIFY.getValue());
        feature.addNumberProperty(Constant.TileStatus.TILE_STATUS, Constant.TileStatus.UN.getValue());
        feature.addStringProperty(Constant.FEATURE_UPDATE_TIME, DateUtil.getCurrentDateTime());
        return feature;
    }

    /**
     * 复制feature
     *
     * @param p 羊毛出在羊身上的要素
     * @param t 要复制到的要素
     * @param c
     * @param a
     * @return
     */
    public static Feature featureCopy(Feature p, Feature t, Map<String, String> c, Map<String, Object> a) {
        if (p == null || t == null) return t;
        if (c == null && a == null) return t;
        if (c != null) {
            String cField;
            JsonElement jsonElement;
            for (String pField : c.keySet()) {
                cField = c.get(pField);
                if (p.hasProperty(pField)) {
                    jsonElement = p.getProperty(pField);
                    t.addProperty(cField, jsonElement);
                }
            }
        }
        if (a != null) {
            Object value;
            for (String key : a.keySet()) {
                value = a.get(key);
                if (value == null) continue;
                if (value instanceof Boolean) {
                    t.addBooleanProperty(key, (Boolean) value);
                } else if (value instanceof String) {
                    t.addStringProperty(key, (String) value);
                } else if (value instanceof Integer || value instanceof Double || value instanceof Long || value instanceof Float || value instanceof Short) {
                    t.addNumberProperty(key, (Number) value);
                } else if (value instanceof Character) {
                    t.addCharacterProperty(key, (Character) value);
                }
            }
        }
        return t;
    }


    /**
     * @param feature
     * @param symbol
     * @return
     */
    public static Feature feature2SymbolFeature(Feature feature, Map<String, Object> symbol) {
        if (feature == null) return null;
        GeoJson centerPoint = Transformation.geoJson2CenterPoint(feature.geometry());
        if (centerPoint == null) return null;
        com.mapbox.geojson.Geometry geometry = (com.mapbox.geojson.Geometry) centerPoint;
        if (centerPoint == null) return null;
        JsonObject attribute = getFeatureAttribute(feature);
        if (symbol != null) {
            Object value;
            for (String key : symbol.keySet()) {
                value = symbol.get(key);
                if (value == null) continue;
                if (value instanceof Boolean) {
                    attribute.addProperty(key, (Boolean) value);
                } else if (value instanceof String) {
                    attribute.addProperty(key, (String) value);
                } else if (value instanceof Integer || value instanceof Double || value instanceof Long || value instanceof Float || value instanceof Short) {
                    attribute.addProperty(key, (Number) value);
                } else if (value instanceof Character) {
                    attribute.addProperty(key, (Character) value);
                }
            }
        }
        return Feature.fromGeometry(geometry, attribute);
    }

    public static JsonObject getFeatureAttribute(Feature feature) {
        if (feature == null) return null;
        return feature.properties();
    }

    public static Object jsonElement2Object(JsonElement jsonElement) {
        if (jsonElement == null) return null;
        if (jsonElement.isJsonNull()) return null;
        if (jsonElement.isJsonPrimitive()) {
            JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive();
            if (jsonPrimitive.isString()) {
                return jsonPrimitive.getAsString();
            } else if (jsonPrimitive.isNumber()) {
                return jsonPrimitive.getAsNumber();
            } else if (jsonPrimitive.isBoolean()) {
                return jsonPrimitive.getAsBoolean();
            }
        }
        return null;
    }

    public static Object getFeatureAttributeAsObject(Feature feature, String attrName) {
        if (feature == null || attrName == null || !feature.hasProperty(attrName)) return null;
        JsonElement jsonElement = feature.getProperty(attrName);
        if (jsonElement == null) return null;
        if (jsonElement.isJsonNull()) return null;
        if (jsonElement.isJsonPrimitive()) {
            JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive();
            if (jsonPrimitive.isString()) {
                return jsonPrimitive.getAsString();
            } else if (jsonPrimitive.isNumber()) {
                return jsonPrimitive.getAsNumber();
            } else if (jsonPrimitive.isBoolean()) {
                return jsonPrimitive.getAsBoolean();
            }
        }
        return null;
    }

    public static <T> T getFeatureAttributeAsT(Feature feature, String attrName) {
        if (feature == null || attrName == null || !feature.hasProperty(attrName)) return null;
        JsonElement jsonElement = feature.getProperty(attrName);
        if (jsonElement == null) return null;
        if (jsonElement.isJsonNull()) return null;
        if (jsonElement.isJsonPrimitive()) {
            JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive();
            if (jsonPrimitive.isString()) {
                return (T) jsonPrimitive.getAsString();
            } else if (jsonPrimitive.isNumber()) {
                return (T) jsonPrimitive.getAsNumber();
            } else if (jsonPrimitive.isBoolean()) {
                boolean b = jsonPrimitive.getAsBoolean();
                return (T) new Boolean(b);
            }
        }
        return null;
    }

    public static <T> List<Feature> featureLeftJoin(List<Feature> features, List<T> os, Map<String, String> mapping) {
        Feature feature;
        Object o = null;
        Object fo, oo;
        List<Feature> featureList = new ArrayList<>();
        for (int i = 0; i < features.size(); i++) {
            feature = features.get(i);
            for (int j = 0; j < os.size(); j++) {
                boolean hasEqual = false;
                o = os.get(j);
                for (String key : mapping.keySet()) {
                    String memberVar = mapping.get(key);
                    fo = getFeatureAttributeAsObject(feature, key);
                    oo = ReflectUtil.getValByNumberVar(o, memberVar);
                    hasEqual = ObjectUtil.baseTypeIsEqual(fo, oo, false);
                    if (!hasEqual) break;
                }
                if (hasEqual) {
                    Feature temp = featureAddExtend(feature, o);
                    featureList.add(temp);
                    break;
                } else {
                    continue;
                }
            }
        }
        return featureList;
    }

    public static Feature featureAddExtend(Feature feature, Object o) {
        String extendJson = GsonFactory.getFactory().getComGson().toJson(o);
        feature.addStringProperty("EXTEND", extendJson);
        return feature;
    }

    public static <T> T featureGetExtend(Feature feature, Class clazz) {
        Gson gson = GsonFactory.getFactory().getComGson();
        String extendJson = feature.getStringProperty("EXTEND");
        return (T) gson.fromJson(extendJson, clazz);
    }
}
